package com.util;

import org.junit.Test;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class TimerDemo {

    /**
     * 延迟两秒，每过一秒输出一条记录
     *
     * @throws InterruptedException
     */
    @Test
    public void test01() throws InterruptedException {
        Timer timer = new Timer();
        System.out.println(Thread.currentThread().getName() + " " + new Date());
        timer.schedule(new TimerTask() {
            public void run() {
                System.out.println(Thread.currentThread().getName() + " " + new Date());
            }
        }, 2000, 1000);

        Thread.sleep(10 * 1000 * 60);
    }


    /**
     * 发现timer其实是单线程，timer线程控制了一个任务队列，通过调用queue中的run方法进行执行。
     * 下面的会发现first任务在启动后的前5s会少执行4次
     *
     * @throws InterruptedException
     */
    @Test
    public void test02() throws InterruptedException {
        Timer timer = new Timer();
        System.out.println(Thread.currentThread().getName() + " " + new Date());
        timer.schedule(new TimerTask() {
            public void run() {
                System.out.println(Thread.currentThread().getName() + " first " + new Date());
            }
        }, 1000, 1000);


        timer.schedule(new TimerTask() {
            public void run() {
                try {
                    Thread.sleep(5 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " second" + new Date());
            }
        }, 0, 10000);

        Thread.sleep(10 * 1000 * 60);
    }

    /**
     * 发现每运行一次 理论运行时间点 和 实际运行时间点 之间的差距新增1s
     * @throws InterruptedException
     */
    @Test
    public void test03() throws InterruptedException {
        Timer timer = new Timer();
        System.out.println(Thread.currentThread().getName() + " " + new Date());
        timer.scheduleAtFixedRate(new TimerTask() {
            public void run() {
                try {
                    Thread.sleep(2 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
                String format = sdf.format(new Date(this.scheduledExecutionTime()));
                String format1 = sdf.format(new Date(System.currentTimeMillis()));
//                System.out.println(Thread.currentThread().getName()+" first " +new Date());
                System.out.println("理论运行时间点：" + format + " 实际运行时间点：" + format1);
            }
        }, 1000, 1000);


        Thread.sleep(3*10*1000);

    }


    /**
     * 采用平衡二进制堆来保存任务。
     */
    @Test
    public void test04() {
        int[] queue = new int[128];
        Integer size = new Integer(0);
        add(2, queue, size++);
        add(19, queue, size++);
        add(3, queue, size++);
        add(4, queue, size++);
        add(1, queue, size++);
        add(6, queue, size++);
        add(5, queue, size++);
        add(7, queue, size++);

        System.out.println(queue);


        System.out.println(removeMin(queue, size--));
        ;
        System.out.println(removeMin(queue, size--));
        ;
        System.out.println(removeMin(queue, size--));
        ;
        System.out.println(removeMin(queue, size--));
        ;
        System.out.println(removeMin(queue, size--));
        ;
        System.out.println(removeMin(queue, size--));
        ;
        System.out.println(removeMin(queue, size--));
        ;
        System.out.println(removeMin(queue, size--));
        ;
    }


    void add(int value, int[] queue, Integer size) {
        // Grow backing store if necessary
        if (size + 1 == queue.length)
            queue = Arrays.copyOf(queue, 2 * queue.length);

        queue[++size] = value;
        fixUp(size, queue);
    }


    int removeMin(int[] queue, Integer size) {
        int result = queue[1];
        queue[1] = queue[size];
        queue[size--] = 0;  // Drop extra reference to prevent memory leak
        fixDown(1, queue, size);
        return result;
    }


    void heapify(Integer size, int[] queue) {
        for (int i = size / 2; i >= 1; i--)
            fixDown(i, queue, size);
    }

    private void fixUp(int k, int[] queue) {
        while (k > 1) {
            int j = k >> 1;
            if (queue[j] <= queue[k])
                break;
            int tmp = queue[j];
            queue[j] = queue[k];
            queue[k] = tmp;
            k = j;
        }
    }

    private void fixDown(int k, int[] queue, Integer size) {
        int j;
        while ((j = k << 1) <= size && j > 0) {
            if (j < size &&
                    queue[j] > queue[j + 1])
                j++; // j indexes smallest kid
            if (queue[k] <= queue[j])
                break;
            int tmp = queue[j];
            queue[j] = queue[k];
            queue[k] = tmp;
            k = j;
        }
    }

}
